//Wrapper for EE::Vec
#pragma once

namespace EsenthelNet
{
	ref struct Matrix;
	ref class Color;

	///<summary>Vector 3D</summary>
	public ref struct Vec {
	internal:
		Vec(EE::Vec v) {
			vec = new EE::Vec();
			*vec = v;
		}
		Vec(EE::Vec* v) {
			vec = v;
		}

		EE::Vec* vec;
	public:
		///<summary>The x component of the vector.</summary>
		Prop(float, X, vec->x)
		///<summary>The y component of the vector.</summary>
		Prop(float, Y, vec->y)
		///<summary>The z component of the vector.</summary>
		Prop(float, Z, vec->z)
	
		///<summary>Makes all components zero.</summary>
		EsenthelNet::Vec^ Zero() { vec->x = vec->y = vec->z = 0; return this; }

		EsenthelNet::Vec^ Set(float r) { vec->x = vec->y = vec->z = r; return this; }

		EsenthelNet::Vec^ Set(float x, float y, float z) { vec->x = x; vec->y = y; vec->z = z; return this; }

		//Operators:
		static EsenthelNet::Vec^ operator +(EsenthelNet::Vec^ v1, float f) { v1->vec->x += f; v1->vec->y += f; v1->vec->z += f; return v1; }
		static EsenthelNet::Vec^ operator -(EsenthelNet::Vec^ v1, float f) { v1->vec->x -= f; v1->vec->y -= f; v1->vec->z -= f; return v1; }
		static EsenthelNet::Vec^ operator *(EsenthelNet::Vec^ v1, float f) { v1->vec->x *= f; v1->vec->y *= f; v1->vec->z *= f; return v1; }
		static EsenthelNet::Vec^ operator /(EsenthelNet::Vec^ v1, float f) { v1->vec->x /= f; v1->vec->y /= f; v1->vec->z /= f; return v1; }

		static EsenthelNet::Vec^ operator +(float f, EsenthelNet::Vec^ v1) { v1->vec->x += f; v1->vec->y += f; v1->vec->z += f; return v1; }
		static EsenthelNet::Vec^ operator -(float f, EsenthelNet::Vec^ v1) { v1->vec->x -= f; v1->vec->y -= f; v1->vec->z -= f; return v1; }
		static EsenthelNet::Vec^ operator *(float f, EsenthelNet::Vec^ v1) { v1->vec->x *= f; v1->vec->y *= f; v1->vec->z *= f; return v1; }
		static EsenthelNet::Vec^ operator /(float f, EsenthelNet::Vec^ v1) { v1->vec->x /= f; v1->vec->y /= f; v1->vec->z /= f; return v1; }

		static EsenthelNet::Vec^ operator +(EsenthelNet::Vec^ v1, EsenthelNet::Vec^ v2) { v1->vec->x += v2->vec->x; v1->vec->y += v2->vec->y; v1->vec->z += v2->vec->z; return v1; }
		static EsenthelNet::Vec^ operator -(EsenthelNet::Vec^ v1, EsenthelNet::Vec^ v2) { v1->vec->x -= v2->vec->x; v1->vec->y -= v2->vec->y; v1->vec->z -= v2->vec->z; return v1; }
		static EsenthelNet::Vec^ operator *(EsenthelNet::Vec^ v1, EsenthelNet::Vec^ v2) { v1->vec->x *= v2->vec->x; v1->vec->y *= v2->vec->y; v1->vec->z *= v2->vec->z; return v1; }
		static EsenthelNet::Vec^ operator /(EsenthelNet::Vec^ v1, EsenthelNet::Vec^ v2) { v1->vec->x /= v2->vec->x; v1->vec->y /= v2->vec->y; v1->vec->z /= v2->vec->z; return v1; }

		static EsenthelNet::Vec^ operator -(EsenthelNet::Vec^ v1) { return gcnew EsenthelNet::Vec(-v1->vec->x, -v1->vec->x, -v1->vec->x); }
		static EsenthelNet::Vec^ operator !(EsenthelNet::Vec^ v1) { EsenthelNet::Vec^ res = v1; res->Normalize(); return res; }

		///<summary>If any component  is  non-zero.</summary>
		bool Any() { return vec->any(); }
		///<summary>If all components are non-zero.</summary>
		bool All() { return vec->all(); }
		///<summary>Components minimum index.</summary>
		int MinI() { return vec->minI(); }
		///<summary>Components maximum index.</summary>
		int MaxI() { return vec->maxI(); }
		///<summary>Components minimum.</summary>
		float Min() { return vec->min(); }
		///<summary>Components maximum.</summary>
		float Max() { return vec->max(); }
		///<summary>Components average</summary>
		float Avg() { return vec->avg(); }
		///<summary>Components sum</summary>
		float Sum() { return vec->sum(); }
		///<summary>Get length.</summary>
		float Length() { return vec->length(); }
		///<summary>Get length^2.</summary>
		float Length2() { return vec->length2(); }
		///<summary>Saturate  length (clamp it to 0..1)</summary>
		void SaturateLength() { vec->satLength(); }
		///<summary>Set length and return previous length.</summary>
		float SetLength(float length) { return vec->setLength(length); }
		///<summary>Clamp length.</summary>
		void ClampLength(float min, float max) { vec->clampLength(min, max); }
		///<summary>Normalize length and return previous length.</summary>
		float Normalize() { return vec->normalize(); }

		///<summary>Transform by 'matrix'.</summary>
		EsenthelNet::Vec^ Mul(EsenthelNet::Matrix^ m);
		///<summary>Transform by 'matrix' inverse, if you know that the matrix is normalized then set 'normalized=true' for more performance</summary>
		EsenthelNet::Vec^ Div(EsenthelNet::Matrix^ m, bool normalized);

		///<summary>Change sign.</summary>
		EsenthelNet::Vec^ Chs() { vec->chs(); return this; }
		///<summary>Absolute value.</summary>
		EsenthelNet::Vec^ Abs() { vec->abs(); return this; }
		///<summary>Saturate.</summary>
		EsenthelNet::Vec^ Sat() { vec->sat(); return this; }


		///<summary>Draw.</summary>
		void Draw(EsenthelNet::Color^ color, float r);
		///<summary>Draw with perspective.</summary>
		void DrawP(EsenthelNet::Color^ color, float r);

		//Static
		static property EsenthelNet::Vec^ Forward { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_FORWARD]); } }
		static property EsenthelNet::Vec^ Backward { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_BACK]); } }
		static property EsenthelNet::Vec^ Right { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_RIGHT]); } }
		static property EsenthelNet::Vec^ Left { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_LEFT]); } }
		static property EsenthelNet::Vec^ Up { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_UP]); } }
		static property EsenthelNet::Vec^ Down { EsenthelNet::Vec^ get() { return gcnew EsenthelNet::Vec(VecDir[DIRE_DOWN]); } }

		Vec() {
			vec = new EE::Vec();
		}
		Vec(float r) {
			vec = new EE::Vec(r);
		}
		Vec(float x, float y, float z) {
			vec = new EE::Vec(x, y, z);
		}

		~Vec() {
			delete vec;
		}


	};
}